<!-- 右键菜单 每一项 -->
<template>
  <div
    class="text-gray-400 relative cursor-pointer"
    :class="{
      'border-b': one.borderBottom,
      'border-gray-500': theme == 'dark',
      'hover:bg-gray-200': theme == 'light',
      'hover:text-gray-600': theme == 'light',
      'hover:bg-blue-500': theme == 'dark',
      'hover:text-white': theme == 'dark',
    }"
    @click.stop="clickItem({ one, data })"
    @mouseenter="config.show = true"
    @mouseleave="config.show = false"
  >
    <span v-if="one.slot">
      <slot :name="one.slot" :item="one" :one="one"></slot>
    </span>
    <div
      v-else
      class="flex justify-between items-center p-2 px-4 text-sm whitespace-nowrap"
      :class="{}"
    >
      <div class="flex items-center">
        <img v-if="one.icon" :src="one.icon" class="w-4 h-4 mr-1" />
        <div
          v-else-if="one.IsIcon == undefined ? IsIcon : one.IsIcon"
          class="w-5 h-5 mr-1"
        ></div>
        <div>{{ one.name }}</div>
      </div>

      <ArrowRight
        v-if="one.children && one.children.length"
        class="w-4 h-4 ml-4"
      />
    </div>

    <div
      v-if="one.children && one.children.length && config.show"
      ref="contextMenuItem"
      class="absolute z-10 rounded shadow"
      :class="{
        'bg-white': theme == 'light',
        'bg-gray-700': theme == 'dark',
        'left-full': !config.IsLeft,
        'right-full': config.IsLeft,
        'top-0': !config.IsBottom,
        'bottom-0': config.IsBottom,
      }"
    >
      <ContextMenuItem
        v-for="(item, index) in one.children"
        :key="index"
        :data="data"
        :menu="menu"
        :one="item"
        :IsLeft="config.IsLeft"
        :IsBottom="config.IsBottom"
        :rightSpace="config.rightSpace"
        :IsIcon="item.IsIcon || IsIcon"
        :theme="theme"
        @select="(e) => emit('select', e)"
      >
        <template v-for="items in slotList()" #[items]>
          <slot :name="items" :item="item" :one="item"></slot>
        </template>
      </ContextMenuItem>
    </div>
  </div>
</template>

<script setup lang="ts" name="ContextMenuItem">
import { reactive, ref, nextTick, watch } from 'vue'

const props: any = defineProps({
  data: [String, Number, Boolean, Array, Object],
  menu: Array as any,
  one: Object as any,
  IsLeft: Boolean,
  IsBottom: Boolean,
  rightSpace: Number,
  IsIcon: Boolean,
  theme: String,
})
const emit = defineEmits(['select'])

// config配置
const config = reactive({
  show: false,
  IsLeft: false, // 是否在左侧
  IsBottom: false, // 是否在右侧
  rightSpace: 0, // 距离右侧空白距离
})
const contextMenuItem = ref()

// 点击
function clickItem({ one, data }: { one: any; data: any }) {
  let { select } = one
  if (select) select({ ...one, data })
  emit('select', { ...one, data })
}

// 设置位置
function setPosition() {
  nextTick(() => {
    let { rightSpace, IsLeft } = props
    let { offsetWidth } = contextMenuItem.value // 当前元素 宽度/高度
    let { clientHeight } = document.documentElement // 屏幕 宽度/高度
    let { top } = contextMenuItem.value.parentNode.getBoundingClientRect() // 父元素 相对屏幕的顶部距离
    let { height } = contextMenuItem.value.getBoundingClientRect() // 当前元素 宽度/高度

    config.rightSpace = rightSpace - offsetWidth
    config.IsLeft = false
    config.IsBottom = false

    if (IsLeft || rightSpace < offsetWidth + 10) config.IsLeft = true
    if (clientHeight - top < height + 10) config.IsBottom = true
  })
}
watch(
  () => config.show,
  (N) => {
    if (!N || !props.one.children || !props.one.children.length) return
    setPosition()
  },
)

// slot多级嵌套
function slotList() {
  const { children } = props.one
  let result: any = []

  let slotCompute = ({ data = [] }) => {
    data.forEach((item) => {
      let { slot, children } = item
      if (slot) result.push(slot)
      if (children) slotCompute({ data: children })
    })
  }
  slotCompute({ data: children })
  result = window.$util.data.uniqueArr({ data: result }) // 去重

  return result
}
</script>

<style lang="scss" scoped></style>
